package pack3_abstractFactory;
import java.lang.reflect.Constructor;

//Human接口：方便在工厂中使用约束泛型 <T extends Human>，接口本质仍然是个类，可以继承
interface FHuman{
    void getColor();
    void getSex();
}

//Human抽象类：方便在工厂中使用约束泛型 <T extends Human>
// abstract class Human{
//     void getColor(){};
//     void getSex(){};
// }

//抽象类：不能实例化, 不用实现所有接口方法
abstract class AbstractBlackFHuman implements FHuman{
    public void getColor(){
        System.out.println("I am a black human");
    }
}

abstract class AbstractWhiteFHuman implements FHuman{
    public void getColor(){
        System.out.println("I am a white human");
    }
}

abstract class AbstractYellowFHuman implements FHuman{
    public void getColor(){
        System.out.println("I am a yellow human");
    }
}

//人种实现类
class MaleBlackFHuman extends AbstractBlackFHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a boy");
    }
}

class FemaleBlackFHuman extends AbstractBlackFHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a girl");
    }
}

class MaleWhiteFHuman extends AbstractWhiteFHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a boy");
    }
}

class FemaleWhiteFHuman extends AbstractWhiteFHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a girl");
    }
}

class MaleYellowFHuman extends AbstractYellowFHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a boy");
    }
}

class FemaleYellowFHuman extends AbstractYellowFHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a girl");
    }
}

/**
 * 相较于code001_abstractFactory，会发现createYellowHuman，createWhiteHuman和createWBlackHuman的代码都是一样的
 * 可否将这三个抽象方法进一步抽象成createHuman()，这样只需要在男女两个子类工厂实现该方法即可，即抽象工厂模式 退化成 工厂模式；
 * Note:
 *   1）如果将问题修改为createChrome，createFireFox和createEdge，由于Chrome、FireFox和createEdge在同一个系统中实现方式是不一样的，
 *   因此不能对这三个抽象方法进一步的抽象；
 */

//实现工厂：将人种实例化过程交给子类工厂去实现，子类工厂包括
class FemaleHumanFFactory{

    public <T extends Human> T createHuman(Class<T> human_clz) {
        T human = null;
        try{
            //构造不同人种
            Constructor constructor = Class.forName(human_clz.getName()).getDeclaredConstructor();
            human = (T) constructor.newInstance();

        }catch(Exception e){
            e.printStackTrace();
        }
        return human;
    }
}

class MaleHumanFFactory{

    public <T extends Human> T createHuman(Class<T> human_clz) {
        T human = null;
        try{
            //构造不同人种
            Constructor constructor = Class.forName(human_clz.getName()).getDeclaredConstructor();
            human = (T) constructor.newInstance();

        }catch(Exception e){
            e.printStackTrace();
        }
        return human;
    }
}

public class code002_abstractFactory_fine{
    public static void main(String[] args) {

        FemaleHumanFFactory fHumanFactory = new FemaleHumanFFactory();
        MaleHumanFFactory mHumanFactory = new MaleHumanFFactory();

        //创建小黄人
        Human h1 = fHumanFactory.createHuman(FemaleYellowHuman.class);
        Human h2 = mHumanFactory.createHuman(MaleYellowHuman.class);
        h1.getSex();
        h2.getSex();

        //创建小黑人
        Human h3 = fHumanFactory.createHuman(FemaleBlackHuman.class);
        Human h4 = mHumanFactory.createHuman(MaleBlackHuman.class);
        h3.getSex();
        h4.getSex();

        //创建小白人
        Human h5 = fHumanFactory.createHuman(FemaleWhiteHuman.class);
        Human h6 = mHumanFactory.createHuman(MaleWhiteHuman.class);
        h5.getSex();
        h6.getSex();
    }
}
